﻿/****************************** Module Header ******************************\

Copyright (c) Gary Davidson

This source is subject to the Microsoft Public License.
See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
All other rights reserved.

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Configuration;
using Microsoft.EnterpriseManagement.ConsoleFramework;
using Microsoft.EnterpriseManagement.UI.SdkDataAccess;
using Microsoft.Win32;

namespace Savviety.ServiceManager.Facade
{
    public class SCSMServer
    {
        private static EnterpriseManagementGroup emg;

        private static readonly Dictionary<Guid, ManagementPack> mpCache = new Dictionary<Guid, ManagementPack>();

        public static bool IsConnected
        {
            get { return CurrentManagementGroup.IsConnected; }
        }

        public static EnterpriseManagementGroup CurrentManagementGroup
        {
            get
            {
               // code gen
                if (emg == null)
                    try
                    {
                        emg = new EnterpriseManagementGroup(
                            Registry.GetValue(
                                @"HKEY_CURRENT_USER\Software\Microsoft\System Center\2010\Service Manager\Console\User Settings",
                                "SDKServiceMachine", "localhost").ToString());
                    }
                    catch (Exception e)
                    {
                        emg.Reconnect();
                    }
                // in console
                if (emg == null)
                {
                    var session =
                        (IManagementGroupSession)FrameworkServices.GetService<IManagementGroupSession>();
                    emg = session.ManagementGroup;
                }

                return emg;


            }
        }

        public static void Reconnect()
        {
            CurrentManagementGroup.Reconnect();
        }

        public static void SetCurrentManagementGroup(string serverName)
        {
            //Guard.NotNullOrEmpty(() => serverName, serverName);

            emg = new EnterpriseManagementGroup(serverName);
        }

        public static void SetCurrentManagementGroup(string serverName, string userName, string password, string domain)
        {
           

            var secureString = new SecureString();
            foreach (char c in password)
                secureString.AppendChar(c);

            secureString.MakeReadOnly();
            var t = new EnterpriseManagementConnectionSettings(serverName);
            

            var settings = new EnterpriseManagementConnectionSettings(serverName)
                               {
                                   UserName = userName,
                                   Domain = domain,
                                   Password = secureString
                               };

            emg = new EnterpriseManagementGroup(settings);
        }


        public static ManagementPack GetSystemManagementPack()
        {
            return GetWellKnownManagementPack(SystemManagementPack.System);
        }

       

        public static ManagementPack GetWellKnownManagementPack(SystemManagementPack systemManagementPack)
        {
            //Guard.NotNull(() => systemManagementPack, systemManagementPack);

            return CurrentManagementGroup.ManagementPacks.GetManagementPack(systemManagementPack);
        }

        public static ManagementPack GetManagementPack(string id)
        {
           

            return GetManagementPack(new Guid(id));
        }

        public static ManagementPack GetManagementPack(Guid managementPackId)
        {
            //Guard.NotDefault(() => managementPackId, managementPackId);

            return mpCache.ContainsKey(managementPackId)
                       ? mpCache[managementPackId]
                       : CurrentManagementGroup.ManagementPacks.GetManagementPack(managementPackId);
        }

        public static ManagementPack GetManagementPack(string name, string keyToken, Version version)
        {
            //Guard.NotNullOrEmpty(() => name, name);
            //Guard.NotNullOrEmpty(() => keyToken, keyToken);

            return CurrentManagementGroup.ManagementPacks.GetManagementPack(name, keyToken, version);
        }

        public static ManagementPack GetManagementPack(string name, Version version)
        {
            //Guard.NotNullOrEmpty(() => name, name);

            return CurrentManagementGroup.ManagementPacks.GetManagementPack(name, null, version);
        }

        public static ManagementPackObjectTemplate GetTemplateFromName(string templateName)
        {
            //Guard.NotNullOrEmpty(() => templateName, templateName);

            var criteria = new ManagementPackObjectTemplateCriteria(string.Format("Name = '{0}'", templateName));
            IList<ManagementPackObjectTemplate> templates =
                CurrentManagementGroup.Templates.GetObjectTemplates(criteria);
            ManagementPackObjectTemplate template = templates.FirstOrDefault();
            if (template == null)
            {
                throw new InvalidOperationException(string.Format("Template '{0}' not found", template));
            }
            return template;
        }

        public static EnterpriseManagementObject GetSingletonObject(ManagementPackClass managementPackClass)
        {
            //Guard.NotNull(() => managementPackClass, managementPackClass);

            const string criteriaString = "DisplayName IS NOT NULL";
            var criteria = new EnterpriseManagementObjectCriteria(criteriaString, managementPackClass);
            IObjectReader<EnterpriseManagementObject> reader =
                CurrentManagementGroup.EntityObjects.GetObjectReader<EnterpriseManagementObject>(criteria,
                                                                                                 ObjectQueryOptions.
                                                                                                     Default);
            EnterpriseManagementObject enterpriseManagementObject = reader.FirstOrDefault();

            return enterpriseManagementObject;
        }

        private static EnterpriseManagementObject GetEnterpriseManagementObject(string criteriaString,
                                                                                ManagementPackClass managementPackClass)
        {
            //Guard.NotNull(() => managementPackClass, managementPackClass);
            //Guard.NotNullOrEmpty(() => criteriaString, criteriaString);

            var criteria = new EnterpriseManagementObjectCriteria(criteriaString, managementPackClass);
            IObjectReader<EnterpriseManagementObject> reader =
                CurrentManagementGroup.EntityObjects.GetObjectReader<EnterpriseManagementObject>(criteria,
                                                                                                 ObjectQueryOptions.
                                                                                                     Default);
            EnterpriseManagementObject enterpriseManagementObject = reader.FirstOrDefault();

            return enterpriseManagementObject;
        }


        public static ManagementPackTypeProjection GetTypeProjection(Guid typeProjectionId)
        {
            //Guard.NotDefault(() => typeProjectionId, typeProjectionId);

            return CurrentManagementGroup.EntityTypes.GetTypeProjection(typeProjectionId);
        }

        public static ManagementPackTypeProjection GetTypeProjection(string className, ManagementPack managementPack)
        {
            //Guard.NotNull(() => managementPack, managementPack);
            //Guard.NotNullOrEmpty(() => className, className);

            return CurrentManagementGroup.EntityTypes.GetTypeProjection(className, managementPack);
        }

        public static ManagementPackTypeProjection GetTypeProjection(string typeProjectionId)
        {
            //Guard.NotNullOrEmpty(() => typeProjectionId, typeProjectionId);

            return GetTypeProjection(new Guid(typeProjectionId));
        }

        public static IList<ManagementPackTypeProjection> GetTypeProjections(ICollection<Guid> ids)
        {
            //Guard.NotOutOfRangeInclusive(() => ids.Count, ids.Count, 1, int.MaxValue);

            return CurrentManagementGroup.EntityTypes.GetTypeProjections(ids);
        }

        public static IList<ManagementPackTypeProjection> GetTypeProjections(
            ManagementPackTypeProjectionCriteria criteria)
        {
            //Guard.NotNull(() => criteria, criteria);

            return CurrentManagementGroup.EntityTypes.GetTypeProjections(criteria);
        }


        public static IObjectReader<EnterpriseManagementObject> GetObjectReader(
            EnterpriseManagementObjectCriteria criteria, ObjectQueryOptions options)
        {
            //Guard.NotNull(() => criteria, criteria);
            return CurrentManagementGroup.EntityObjects.GetObjectReader<EnterpriseManagementObject>(criteria, options);
        }

        public static IObjectProjectionReader<EnterpriseManagementObject> GetObjectProjectionReader(
            ObjectProjectionCriteria criteria, ObjectQueryOptions options)
        {
            //Guard.NotNull(() => criteria, criteria);
            return CurrentManagementGroup.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(criteria,
                                                                                                              options);
        }


        public static ManagementPackClass GetClass(Guid classId)
        {
            //Guard.NotDefault(() => classId, classId);

            return CurrentManagementGroup.EntityTypes.GetClass(classId);
        }

        public static ManagementPackClass GetClass(string classId)
        {
            //Guard.NotNullOrEmpty(() => classId, classId);
            return CurrentManagementGroup.EntityTypes.GetClass(new Guid(classId));
        }

        public static ManagementPackClass GetClass(string className, ManagementPack managementPack)
        {
            //Guard.NotNull(() => managementPack, managementPack);
            //Guard.NotNullOrEmpty(() => className, className);
            return CurrentManagementGroup.EntityTypes.GetClass(className, managementPack);
        }

        public static IList<ManagementPackClass> GetClasses(Guid[] guids)
        {
            //Guard.NotOutOfRangeExclusive(() => guids.Count(), guids.Count(), 0, int.MaxValue);
            return CurrentManagementGroup.EntityTypes.GetClasses(guids);
        }

        public static IList<ManagementPackClass> GetClasses(ManagementPackClassCriteria classCriteria)
        {
            //Guard.NotNull(() => classCriteria, classCriteria);
            return CurrentManagementGroup.EntityTypes.GetClasses(classCriteria);
        }

        public static ManagementPackEnumeration GetEnumeration(Guid enumerationId)
        {
            //Guard.NotDefault(() => enumerationId, enumerationId);
            return CurrentManagementGroup.EntityTypes.GetEnumeration(enumerationId);
        }


        public static CreatableEnterpriseManagementRelationshipObject GetRelationshipObject(Guid relationshipId)
        {
            //Guard.NotDefault(() => relationshipId, relationshipId);
            ManagementPackRelationship @class = GetRelationshipClass(relationshipId);
            return new CreatableEnterpriseManagementRelationshipObject(CurrentManagementGroup, @class);
        }

        public static CreatableEnterpriseManagementRelationshipObject GetRelationshipObject(string relationshipId)
        {
            //Guard.NotNullOrEmpty(() => relationshipId, relationshipId);
            return GetRelationshipObject(new Guid(relationshipId));
        }


        public static ManagementPackRelationship GetRelationshipClass(Guid relationshipClassId)
        {
            //Guard.NotDefault(() => relationshipClassId, relationshipClassId);

            return CurrentManagementGroup.EntityTypes.GetRelationshipClass(relationshipClassId);
        }

        public static ManagementPackRelationship GetRelationshipClass(string relationshipClassId)
        {
            //Guard.NotDefault(() => relationshipClassId, relationshipClassId);
            return GetRelationshipClass(new Guid(relationshipClassId));
        }

        public static ManagementPackRelationship GetRelationshipClass(string typeName, ManagementPack managementPack)
        {

            //Guard.NotNull(() => managementPack, managementPack);
            //Guard.NotNullOrEmpty(() => typeName, typeName);
            return CurrentManagementGroup.EntityTypes.GetRelationshipClass(typeName, managementPack);
        }

        public static ManagementPackRelationship GetRelationshipClass(SystemRelationship relationship)
        {
            //Guard.NotNull(() => relationship, relationship);
            return CurrentManagementGroup.EntityTypes.GetRelationshipClass(relationship);
        }

        public static CreatableEnterpriseManagementObject GetCreatableEnterpriseManagementObject(
            ManagementPackClass typeToCreate)
        {

            //Guard.NotNull(() => typeToCreate, typeToCreate);
            return new CreatableEnterpriseManagementObject(CurrentManagementGroup, typeToCreate);
        }

        public static CreatableEnterpriseManagementObject GetCreatableEnterpriseManagementObject(ManagementPackObjectTemplate managementPackObjectTemplate)
        {

            //Guard.NotNull(() => managementPackObjectTemplate, managementPackObjectTemplate);
            return new CreatableEnterpriseManagementObject(CurrentManagementGroup, managementPackObjectTemplate);
        }

        public static CreatableEnterpriseManagementObject GetCreatableEnterpriseManagementObject(ManagementPackObjectTemplate managementPackObjectTemplate, ObjectTemplateCallback callback)
        {
            //Guard.NotNull(() => managementPackObjectTemplate, managementPackObjectTemplate);
            //Guard.NotNull(() => callback, callback);
            return new CreatableEnterpriseManagementObject(CurrentManagementGroup, managementPackObjectTemplate,callback);
        }


        // add commonly used Management Pack Classes here

        public static T GetObject<T>(Guid id) where T : EnterpriseManagementObject
        {
            //Guard.NotDefault(() => id, id);
            return CurrentManagementGroup.EntityObjects.GetObject<T>(id, ObjectQueryOptions.Default);
        }

        public static T GetObject<T>(string id) where T : EnterpriseManagementObject
        {
            //Guard.NotNullOrEmpty(() => id, id);
            return CurrentManagementGroup.EntityObjects.GetObject<T>(new Guid(id), ObjectQueryOptions.Default);
        }
    }
}